package praktikum_1_ylesanded;

import com.google.common.base.Joiner;

import java.util.ArrayList;
import java.util.HashMap;

/**
 * Created by IntelliJ IDEA.
 * User: Jaan Sepp
 * Date: 20.09.11
 * Time: 21:11
 * To change this template use File | Settings | File Templates.
 */
public class MathHelper {

  public String getFibonacciNumbersRecursively(String[] originalNumbers) {
    ArrayList<Integer> fibonacciNumbers = new ArrayList<Integer>();
    for (String originalNumber : originalNumbers) {
      int currentNumber = Integer.parseInt(originalNumber);
      fibonacciNumbers.add(calculateFibonacciNumberRecursively(currentNumber));
    }
    return Joiner.on("\n").join(fibonacciNumbers) + "\n";
  }

  private int calculateFibonacciNumberRecursively(int number) {
    if (number < 3)
      return 1;
    else
      return calculateFibonacciNumberRecursively(number - 1) + calculateFibonacciNumberRecursively(number - 2);
  }

  public String getFibonacciNumbersIteratively(String[] originalNumbers) {
    ArrayList<Double> fibonacciNumbers = new ArrayList<Double>();
    for (String originalNumber : originalNumbers) {
      int currentNumber = Integer.parseInt(originalNumber);
      fibonacciNumbers.add(calculateFibonacciNumberIteratively(currentNumber));
    }
    return Joiner.on("\n").join(fibonacciNumbers) + "\n";
  }

  private Double calculateFibonacciNumberIteratively(int number) {
    Double firstNumber = 1.0;
    Double secondNumber = 1.0;
    for (int i = 3; i <= number; i++) {
      Double thirdNumber = firstNumber + secondNumber;
      firstNumber = secondNumber;
      secondNumber = thirdNumber;
    }
    return secondNumber;
  }

  public HashMap<String, Integer> getFibonacciNumbersRecursivelyWithTime(long time) {
    long timeTaken = 0;
    int currentNumber = 0;
    long previousTime;

    do {
      long currentTime = System.currentTimeMillis();
      calculateFibonacciNumberRecursively(currentNumber);
      previousTime = timeTaken;
      timeTaken = System.currentTimeMillis() - currentTime;
      System.out.println("Calculating fibonacci number " + currentNumber + " took " + timeTaken + ".");
      currentNumber++;
    } while (timeTaken < time + 1);

    HashMap<String, Integer> lastNumberInfo = new HashMap<String, Integer>();
    lastNumberInfo.put("number",currentNumber - 2);
    lastNumberInfo.put("time",(int)previousTime);
    return lastNumberInfo;
  }

  @SuppressWarnings({"NumericOverflow"})
  public Double getFibonacci400(int number, int timeTaken) {
    System.out.println("Arv: " + number + ", aeg: " + timeTaken);
    // Get rows for the number that can be calculated within 1 second.
    Double rows = (3 * calculateFibonacciNumberIteratively(number) - 2);

    // How much time it takes to calculate 1 row.
    Double timePerRow = timeTaken/rows;

    // Calculate how many rows there are in fib(400).
    Double Fibonacci400Rows = calculateFibonacciNumberIteratively(400) * (3.0) - 2.0;

    // Calculate the time it takes to calculate Fib(400) on this computer.
    Double timeFor400 = Fibonacci400Rows * timePerRow;
    return timeFor400 / (1000 * 60 * 60 * 24 * 365);
  }
}
